package org.colafries.common.utils.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;

import java.io.ByteArrayOutputStream;
import java.util.*;

/**
 * @author colafries
 * @version v1.0
 * @ClassName DynamicEasyExcelExportUtils
 * @Description excel导出工具类
 * @date Created in 2024/5/9
 **/
@Slf4j
public class DynamicEasyExcelExportUtils {
    private static final String DEFAULT_SHEET_NAME = "sheet1";

    /**
     * 动态导出文件（不带字典）
     *
     * @param excelHeadColumnMap 有序列头部
     * @param dataList           数据体
     * @return
     */
    public static byte[] exportExcelFile(LinkedHashMap<String, String> excelHeadColumnMap, List<LinkedHashMap<String, Object>> dataList) {
        //获取列名称
        List<List<String>> excelHead = new ArrayList<>();
        if (MapUtils.isNotEmpty(excelHeadColumnMap)) {
            //key为匹配符，value为列名，如果多级列名用逗号隔开
            excelHeadColumnMap.forEach((key, value) -> excelHead.add(Lists.newArrayList(value.split(","))));
        }
        List<List<Object>> excelRows = new ArrayList<>();
        if (MapUtils.isNotEmpty(excelHeadColumnMap) && CollectionUtils.isNotEmpty(dataList)) {
            for (LinkedHashMap dataMap : dataList) {
                List<Object> rows = new ArrayList<>();
                excelHeadColumnMap.forEach((key, value) -> {
                    if (dataMap.containsKey(key)) {
                        Object data = dataMap.get(key);
                        rows.add(data);
                    }
                });
                excelRows.add(rows);
            }
        }
        return createExcelFile(excelHead, excelRows);
    }

    /**
     * 动态导出文件（带字典）
     *
     * @param headColumn
     * @param dictionary
     * @param dataList
     * @return
     */
    public static byte[] exportExcelFile(LinkedHashMap<String, String> headColumn,
                                         LinkedHashMap<String, List<LinkedHashMap>> dictionary,
                                         List<LinkedHashMap<String, Object>> dataList) {
        // 列字典是否为空 默认为空
        boolean columnDicMapEmptyFlag = true;
        for (List<LinkedHashMap> dicList : dictionary.values()) {
            // 判断该 List 是否有元素
            if (dicList != null && !dicList.isEmpty()) {
                columnDicMapEmptyFlag = false; // 如果有任意一个 List 的 size > 0，则为 false
                break;
            }
        }
        // 如果字典为空
        if (columnDicMapEmptyFlag) {
            return exportExcelFile(headColumn, dataList);
        }

        //获取列名称
        List<List<String>> excelHead = new ArrayList<>();
        if (MapUtils.isNotEmpty(headColumn)) {
            //key为匹配符，value为列名，如果多级列名用逗号隔开
            headColumn.forEach((key, value) -> excelHead.add(Lists.newArrayList(value.split(","))));
        }

        List<List<Object>> excelRows = new ArrayList<>();
        if (MapUtils.isNotEmpty(headColumn) && CollectionUtils.isNotEmpty(dataList)) {
            for (LinkedHashMap dataMap : dataList) {
                List<Object> rows = new ArrayList<>();
                headColumn.forEach((key, value) -> {
                    if (dataMap.containsKey(key)) {
                        Object data = dataMap.get(key);
                        rows.add(data);
                    }
                });
                excelRows.add(rows);
            }
        }
        // 使用处理后的数据来生成 Excel 文件
        return createExcelFile(excelHead, excelRows, dictionary);
    }


    /**
     * 生成Excel文件（不带字典）
     *
     * @param excelHead
     * @param excelRows
     * @return
     */
    private static byte[] createExcelFile(List<List<String>> excelHead, List<List<Object>> excelRows) {
        try {
            if (CollectionUtils.isNotEmpty(excelHead)) {
                // 1. 调整表头，预留序号列位置
                List<List<String>> newExcelHead = new ArrayList<>();
                List<String> SerialNumberColumn = new ArrayList<>();
                SerialNumberColumn.add("序号");
                newExcelHead.add(SerialNumberColumn);
                newExcelHead.addAll(excelHead);

                // 2. 调整数据，预留序号列位置
                List<List<Object>> newExcelRows = new ArrayList<>();
                for (List<Object> row : excelRows) {
                    List<Object> newRow = new ArrayList<>();
                    newRow.add(null);  // 占位，实际内容由 SerialNumberHandler 填充
                    newRow.addAll(row);
                    newExcelRows.add(newRow);
                }

                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                EasyExcel.write(outputStream)
                        .head(newExcelHead)
                        .useDefaultStyle(false)
                        .registerWriteHandler(new SerialNumberHandler())
                        .sheet(DEFAULT_SHEET_NAME)
                        .doWrite(newExcelRows);
                return outputStream.toByteArray();
            }
        } catch (Exception e) {
            log.error("动态生成excel文件失败，headColumns：" + JSONArray.toJSONString(excelHead) + "，excelRows：" + JSONArray.toJSONString(excelRows), e);
        }
        return null;
    }

    /**
     * 生成Excel文件（不带字典）
     *
     * @param excelHead
     * @param excelRows
     * @param tableColumnDicMap
     * @return
     */
    private static byte[] createExcelFile(List<List<String>> excelHead,
                                          List<List<Object>> excelRows,
                                          LinkedHashMap<String, List<LinkedHashMap>> tableColumnDicMap) {
        try {
            if (CollectionUtils.isNotEmpty(excelHead)) {
                // 1. 调整表头，预留序号列位置
                List<List<String>> newExcelHead = new ArrayList<>();
                List<String> SerialNumberColumn = new ArrayList<>();
                SerialNumberColumn.add("序号");
                newExcelHead.add(SerialNumberColumn);
                newExcelHead.addAll(excelHead);

                // 2. 调整数据，预留序号列位置
                List<List<Object>> newExcelRows = new ArrayList<>();
                for (List<Object> row : excelRows) {
                    List<Object> newRow = new ArrayList<>();
                    newRow.add(null);  // 占位，实际内容由 SerialNumberHandler 填充
                    newRow.addAll(row);
                    newExcelRows.add(newRow);
                }

                // 3. 生成下拉框选项
                Map<Integer, String[]> dropDownOptions = generateDropDownOptions(tableColumnDicMap);

                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                EasyExcel.write(outputStream)
                        .head(newExcelHead)
                        .useDefaultStyle(false)
                        .registerWriteHandler(new SerialNumberHandler())
                        .registerWriteHandler(new DropDownHandler(dropDownOptions))  // 使用下拉框选项
                        .sheet(DEFAULT_SHEET_NAME)
                        .doWrite(newExcelRows);
                return outputStream.toByteArray();
            }
        } catch (Exception e) {
            log.error("动态生成excel文件失败，headColumns：" + JSONArray.toJSONString(excelHead) + "，excelRows：" + JSONArray.toJSONString(excelRows), e);
        }
        return null;
    }

    /**
     * 生成下拉框选项
     *
     * @param tableColumnDicMap 字典（列索引 -> 下拉框选项）
     * @return
     */
    private static Map<Integer, String[]> generateDropDownOptions(LinkedHashMap<String, List<LinkedHashMap>> tableColumnDicMap) {
        Map<Integer, String[]> dropDownOptions = new HashMap<>();
        // 从第二列开始
        // 默认：第一列为序号
        int columnIndex = 1;
        for (Map.Entry<String, List<LinkedHashMap>> entry : tableColumnDicMap.entrySet()) {
            List<LinkedHashMap> dicList = entry.getValue();
            if (CollectionUtils.isNotEmpty(dicList)) {
                String[] options = dicList.stream()
                        .map(dic -> dic.get("value").toString())
                        .toArray(String[]::new);
                dropDownOptions.put(columnIndex, options);
            }
            columnIndex++;
        }
        return dropDownOptions;
    }
}